"use client";
 
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { FileIcon, FolderClosedIcon } from "lucide-react";
import React, {
  createContext,
  forwardRef,
  useCallback,
  useContext,
  useEffect,
  useState,
} from "react";
import { Button } from "@/components/ui/button";
import { TriangleIcon } from "./helper";
 
type TreeViewElement = {
  id: string;
  name: string;
  isSelectable?: boolean;
  children?: TreeViewElement[];
};
 
type TreeContextProps = {
  selectedId: string | undefined;
  expendedItems: string[] | undefined;
  indicator: boolean;
  handleExpand: (id: string) => void;
  selectItem: (id: string) => void;
  setExpendedItems?: React.Dispatch<React.SetStateAction<string[] | undefined>>;
  direction: "rtl" | "ltr";
  separateClickActions: boolean; // 新增：是否分离点击行为
};
 
const TreeContext = createContext<TreeContextProps | null>(null);
 
const useTree = () => {
  const context = useContext(TreeContext);
  if (!context) {
    throw new Error("useTree must be used within a TreeProvider");
  }
  return context;
};
 
interface TreeViewComponentProps extends React.HTMLAttributes<HTMLDivElement> {}
 
type Direction = "rtl" | "ltr" | undefined;
 
type TreeViewProps = {
  initialSelectedId?: string;
  indicator?: boolean;
  elements?: TreeViewElement[];
  initialExpendedItems?: string[];
  openIcon?: React.ReactNode;
  closeIcon?: React.ReactNode;
  separateClickActions?: boolean; // 新增：是否分离点击行为
} & TreeViewComponentProps;
 
/**
 * Tree View Docs: {@link: https://shadcn-extension.vercel.app/docs/tree-view}
 */
 
const Tree = forwardRef<HTMLDivElement, TreeViewProps>(
  (
    {
      className,
      elements,
      initialSelectedId,
      initialExpendedItems,
      children,
      indicator,
      openIcon,
      closeIcon,
      dir,
      separateClickActions = false, // 默认为false，保持原有行为
      ...props
    },
    ref,
  ) => {
    const [selectedId, setSelectedId] = useState<string | undefined>(
      initialSelectedId,
    );
    const [expendedItems, setExpendedItems] = useState<string[] | undefined>(
      initialExpendedItems,
    );
 
    const selectItem = useCallback((id: string) => {
      setSelectedId(id);
    }, []);
 
    const handleExpand = useCallback((id: string) => {
      setExpendedItems((prev) => {
        if (prev?.includes(id)) {
          return prev.filter((item) => item !== id);
        }
        return [...(prev ?? []), id];
      });
    }, []);
 
    const expandSpecificTargetedElements = useCallback(
      (elements?: TreeViewElement[], selectId?: string) => {
        if (!elements || !selectId) return;
        const findParent = (
          currentElement: TreeViewElement,
          currentPath: string[] = [],
        ) => {
          const isSelectable = currentElement.isSelectable ?? true;
          const newPath = [...currentPath, currentElement.id];
          if (currentElement.id === selectId) {
            if (isSelectable) {
              setExpendedItems((prev) => [...(prev ?? []), ...newPath]);
            } else {
              if (newPath.includes(currentElement.id)) {
                newPath.pop();
                setExpendedItems((prev) => [...(prev ?? []), ...newPath]);
              }
            }
            return;
          }
          if (
            isSelectable &&
            currentElement.children &&
            currentElement.children.length > 0
          ) {
            currentElement.children.forEach((child) => {
              findParent(child, newPath);
            });
          }
        };
        elements.forEach((element) => {
          findParent(element);
        });
      },
      [],
    );
 
    useEffect(() => {
      if (initialSelectedId) {
        expandSpecificTargetedElements(elements, initialSelectedId);
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [initialSelectedId, elements]);
 
    const direction = dir === "rtl" ? "rtl" : "ltr";
 
    return (
      <TreeContext.Provider
        value={{
          selectedId,
          expendedItems,
          handleExpand,
          selectItem,
          setExpendedItems,
          indicator:false,
          direction,
          separateClickActions,
        }}
      >
        <div className={cn("size-full", className)}>
          <ScrollArea
            ref={ref}
            className="h-full relative pl-2 pr-3"
            dir={dir as Direction}
          >
            <AccordionPrimitive.Root
              {...props}
              type="multiple"
              defaultValue={expendedItems}
              value={expendedItems}
              className="flex flex-col gap-1 w-full!"
              onValueChange={(value) =>
                setExpendedItems((prev) => [...(prev ?? []), value[0]])
              }
              dir={dir as Direction}
            >
              {children}
            </AccordionPrimitive.Root>
          </ScrollArea>
        </div>
      </TreeContext.Provider>
    );
  },
);
 
Tree.displayName = "Tree";
 
const TreeIndicator = forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
  const { direction } = useTree();
 
  return (
    <div
      dir={direction}
      ref={ref}
      className={cn(
        "h-full z-[-1] w-px bg-muted absolute left-3.5 rtl:right-3.5 duration-300 ease-in-out",
        className,
      )}
      {...props}
    />
  );
});
 
TreeIndicator.displayName = "TreeIndicator";
 
interface FolderComponentProps
  extends React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> {}
 
type FolderProps = {
  expendedItems?: string[];
  element: string;
  isSelectable?: boolean;
  isSelect?: boolean;
  folderIcon?: boolean;
} & FolderComponentProps;
 
const Folder = forwardRef<
  HTMLDivElement,
  FolderProps & React.HTMLAttributes<HTMLDivElement>
>(
  (
    {
      className,
      element,
      value,
      isSelectable = true,
      isSelect,
      folderIcon = true,
      children,
      ...props
    },
    ref,
  ) => {
    const {
      direction,
      handleExpand,
      expendedItems,
      indicator,
      setExpendedItems,
      selectedId,
      selectItem,
      separateClickActions,
    } = useTree();

    const isSelected = isSelect ?? selectedId === value;

    return (
      <AccordionPrimitive.Item
        {...props}
        value={value}
        className="relative overflow-hidden h-full z-10"
      >
        {separateClickActions ? (
          // 分离点击行为：三角形只展开/折叠，其他区域只选中
          <div
            className={cn(
              `flex items-center gap-1 text-sm rounded-md h-9 bg-inherit hover:bg-muted w-full duration-200 ease-in-out px-1.5`,
              `hover:bg-[#EBF1FF] hover:text-[#4A4FED]`,
              className,
              {
                "bg-[#EBF1FF] text-[#4A4FED]": isSelected && isSelectable,
                "cursor-pointer": isSelectable,
                "cursor-not-allowed opacity-50": !isSelectable,
              },
            )}
            onClick={(e) => {
              // 只有点击非三角形区域时才选中
              if (isSelectable && !(e.target as HTMLElement).closest('.triangle-icon')) {
                selectItem(value);
              }
            }}
          >
            <AccordionPrimitive.Trigger
              className="triangle-icon p-0 bg-transparent border-none hover:bg-transparent"
              disabled={!isSelectable}
              onClick={(e) => {
                e.stopPropagation();
                handleExpand(value);
              }}
            >
              <TriangleIcon
                className={cn("size-4 duration-200 ease-in-out cursor-pointer", {
                  "rotate-90": expendedItems?.includes(value),
                  "rotate-0": !expendedItems?.includes(value),
                })}
              />
            </AccordionPrimitive.Trigger>
            <span
              className="flex items-center gap-1 flex-1 cursor-pointer"
              onClick={() => {
                if (isSelectable) {
                  selectItem(value);
                }
              }}
            >
              {folderIcon && <FolderClosedIcon className="size-4" />}
              <span>{element}</span>
            </span>
          </div>
        ) : (
          // 原有行为：点击任何位置都展开/折叠+选中
          <AccordionPrimitive.Trigger
            className={cn(
              `flex items-center gap-1 text-sm rounded-md h-9 bg-inherit hover:bg-muted w-full duration-200 ease-in-out px-1.5`,
              `hover:bg-[#EBF1FF] hover:text-[#4A4FED]`,
              className,
              {
                "bg-[#EBF1FF] text-[#4A4FED]": isSelected && isSelectable,
                "cursor-pointer": isSelectable,
                "cursor-not-allowed opacity-50": !isSelectable,
              },
            )}
            disabled={!isSelectable}
            onClick={() => {
              handleExpand(value);
              if (isSelectable) {
                selectItem(value);
              }
            }}
          >
            <TriangleIcon
              className={cn("size-4 duration-200 ease-in-out", {
                "rotate-90": expendedItems?.includes(value),
                "rotate-0": !expendedItems?.includes(value),
              })}
            />
            <span className="flex items-center gap-1">
              {folderIcon && <FolderClosedIcon className="size-4" />}
              <span>{element}</span>
            </span>
          </AccordionPrimitive.Trigger>
        )}
        <AccordionPrimitive.Content className="text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down relative overflow-hidden h-full">
          {element && indicator && <TreeIndicator aria-hidden="true" />}
          <AccordionPrimitive.Root
            dir={direction}
            type="multiple"
            className="flex flex-col gap-1 py-1 pl-[1.625rem] rtl:pr-[1.625rem]"
            defaultValue={expendedItems}
            value={expendedItems}
            onValueChange={(value) => {
              setExpendedItems?.((prev) => [...(prev ?? []), value[0]]);
            }}
          >
            {children}
          </AccordionPrimitive.Root>
        </AccordionPrimitive.Content>
      </AccordionPrimitive.Item>
    );
  },
);
 
Folder.displayName = "Folder";
 
const File = forwardRef<
  HTMLButtonElement,
  {
    value: string;
    handleSelect?: (id: string) => void;
    isSelectable?: boolean;
    isSelect?: boolean;
    fileIcon?: React.ReactNode;
  } & React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(
  (
    {
      value,
      className,
      handleSelect,
      isSelectable = true,
      isSelect,
      fileIcon,
      children,
      ...props
    },
    ref,
  ) => {
    const { direction, selectedId, selectItem } = useTree();
    const isSelected = isSelect ?? selectedId === value;
    return (
      <AccordionPrimitive.Item
        value={value}
        onClick={() => selectItem(value)}
        className={cn(
          "relative",
          isSelectable ? "cursor-pointer" : "opacity-50 cursor-not-allowed",
        )}
      >
        <AccordionPrimitive.Trigger
          ref={ref}
          {...props}
          dir={direction}
          disabled={!isSelectable}
          aria-label="File"
          className={cn(
            "flex items-center gap-1 cursor-pointer text-sm pr-1 rtl:pl-1 rtl:pr-0 h-9",
            "rounded-md duration-200 ease-in-out pl-2 rtl:pr-2 w-full",
            "hover:bg-[#EBF1FF] hover:text-[#4A4FED]",
            {
              "bg-[#EBF1FF] text-[#4A4FED]": isSelected && isSelectable,
            },
            className,
          )}
        >
          {fileIcon ?? <FileIcon className="h-4 w-4" />}
          {children}
        </AccordionPrimitive.Trigger>
      </AccordionPrimitive.Item>
    );
  },
);
 
File.displayName = "File";
 
const CollapseButton = forwardRef<
  HTMLButtonElement,
  {
    elements: TreeViewElement[];
    expandAll?: boolean;
  } & React.HTMLAttributes<HTMLButtonElement>
>(({ className, elements, expandAll = false, children, ...props }, ref) => {
  const { expendedItems, setExpendedItems } = useTree();
 
  const expendAllTree = useCallback((elements: TreeViewElement[]) => {
    const expandTree = (element: TreeViewElement) => {
      const isSelectable = element.isSelectable ?? true;
      if (isSelectable && element.children && element.children.length > 0) {
        setExpendedItems?.((prev) => [...(prev ?? []), element.id]);
        element.children.forEach(expandTree);
      }
    };
 
    elements.forEach(expandTree);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
 
  const closeAll = useCallback(() => {
    setExpendedItems?.([]);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
 
  useEffect(() => {
    console.log(expandAll);
    if (expandAll) {
      expendAllTree(elements);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [expandAll]);
 
  return (
    <Button
      variant={"ghost"}
      className="w-fit absolute bottom-1 right-2"
      onClick={
        expendedItems && expendedItems.length > 0
          ? closeAll
          : () => expendAllTree(elements)
      }
      ref={ref}
      {...props}
    >
      {children}
      <span className="sr-only">Toggle</span>
    </Button>
  );
});
 
CollapseButton.displayName = "CollapseButton";
 
export { Tree, Folder, File, CollapseButton, type TreeViewElement };
